package net.sea.commons.util.zip;

import java.io.*;
import java.util.Vector;

/**
 * 
 * @author wangwei
 */
public class FileSystemManager {

	/**
	 * test whether the file or directory denoted by this abstract pathname
	 * exists.
	 * 
	 * @param strFullPath
	 *            a path name string.
	 * @return boolean ture if and only if the file denoted by this abstract
	 *         pathname exists.false otherwise.
	 */
	public static boolean fileExisted(String strFullPath) {
		if (strFullPath == null)
			return false;
		return new File(strFullPath).exists();
	}

	/**
	 * Create the directroy named by this abstract pathname.
	 * 
	 * @param strFullPath
	 *            a path name stirng.
	 * @return boolean true if and only if the directory was created,along with
	 *         all necessary parent directorys.false otherwise.
	 */
	public static synchronized boolean makeDir(String strFullPath) {
		if (strFullPath == null)
			return false;
		if (fileExisted(strFullPath))
			return true;
		strFullPath = processPath(strFullPath);
		return new File(strFullPath).mkdirs();
	}

	/**
	 * Create a new,empty file named by this abstract pathname.if and only if a
	 * file with this name does not exist.
	 * 
	 * @param strFullPath
	 *            a file name string.
	 * @return boolean ture if and only if the named file does not exist and was
	 *         successfully created.false if the named file already exists.
	 */
	public static synchronized boolean newFile(String strFullPath) {
		if (strFullPath == null)
			return false;
		strFullPath = processFileAbsPath(strFullPath);
		String strDelim = "";
		// System.getProperty("file.separator");
		if (strFullPath.indexOf("\\") != -1)
			strDelim = "\\";
		else if (strFullPath.indexOf("/") != -1)
			strDelim = "/";
		else
			return false;

		if (!strFullPath.endsWith(strDelim)) {
			String strFilePath = strFullPath.substring(0,
					strFullPath.lastIndexOf(strDelim));

			if (!fileExisted(strFilePath))
				if (!makeDir(strFilePath))
					return false;
		}

		if (fileExisted(strFullPath))
			return true;

		try {
			return new File(strFullPath).createNewFile();
		} catch (IOException ie) {
			ie.printStackTrace();
			return false;
		}
	}

	public static String processPath(String strPath) {
		String strDelim = getSysPathDelim();
		if (strPath == null)
			return null;
		if (strPath.startsWith(("." + strDelim)))
			strPath = strPath.substring(strPath.indexOf(("." + strDelim)) + 2);

		while (strPath.indexOf("\\") != -1)
			strPath = strPath.replace('\\', '/');

		// modified 2003/11/17,order to fix bug.
		// while path contain '.' ,for example:f:\tomcat4.1\config
		// path can't complete path with system delim.

		if (!strPath.endsWith("\\") && !strPath.endsWith("/"))
			if (strPath.lastIndexOf(".") < strPath.lastIndexOf("/"))
				strPath = strPath + "/";

		// if path contain double slash('//') then remove one slash
		int preIndex = -999;
		int index = -999;

		while ((index = strPath.indexOf("/", preIndex + 1)) != -1) {
			if (index == preIndex + 1) {
				strPath = strPath.substring(0, index)
						+ strPath.substring(index + 1);
			}

			preIndex = index;
		}
		return strPath;
	}

	public static String processFileAbsPath(String strPath) {
		String strDelim = getSysPathDelim();
		if (strPath == null)
			return null;
		if (strPath.startsWith(("." + strDelim)))
			strPath = strPath.substring(strPath.indexOf(("." + strDelim)) + 2);

		while (strPath.indexOf("\\") != -1)
			strPath = strPath.replace('\\', '/');

		// if path contain double slash('//') then remove one slash
		int preIndex = -999;
		int index = -999;

		while ((index = strPath.indexOf("/", preIndex + 1)) != -1) {
			if (index == preIndex + 1) {
				strPath = strPath.substring(0, index)
						+ strPath.substring(index + 1);
			}

			preIndex = index;
		}
		return strPath;
	}

	public static String replaceItemInPath(String strPath, String strOldItem,
			String strNewItem) {
		if (strPath.equals("") || strOldItem.equals(""))
			return strPath;
		int index = strPath.indexOf(strOldItem);
		if (index == -1)
			return strPath;

		String strLeft = strPath.substring(0, index);
		String strRight = strPath.substring(index + strOldItem.length());
		return strLeft + strNewItem + strRight;
	}

	public static String getSysPathDelim() {
		return System.getProperty("file.separator");
	}

	public static File[] listDirectory(String strAbsolutedPath) {
		return listDirectory(strAbsolutedPath, false);
	}

	public static File[] listDirectory(String strAbsolutedPath,
			boolean includeDir) {
		return listDirectory(strAbsolutedPath, null, includeDir);
	}

	public static File[] listDirectory(String strAbsolutedPath,
			FilenameFilter filter, boolean includeDir) {
		Vector<File> vt = new Vector<File>();
		scanFiles(strAbsolutedPath, vt, filter, includeDir);
		int count = vt.size();
		File[] fs = new File[count];
		vt.toArray(fs);
		return fs;
	}

	private static void scanFiles(String strAbsolutedPath, Vector<File> vt,
			FilenameFilter filter, boolean includeDir) {
		File f = new File(strAbsolutedPath);
		if (!f.exists())
			return;

		File[] fs = filter == null ? f.listFiles() : f.listFiles(filter);
		for (int i = 0; i < fs.length; i++) {
			if (fs[i].isDirectory()) {
				if (includeDir)
					vt.add(fs[i]);
				scanFiles(fs[i].getAbsolutePath(), vt, filter, includeDir);
			} else
				vt.add(fs[i]);
		}
	}

	public static String[] listSubDir(String strAusolutedPath,
			boolean onlyIncludeFile) {
		Vector<String> vct = new Vector<String>();
		if (strAusolutedPath == null)
			return null;
		File f = new File(strAusolutedPath);
		File[] files = f.listFiles();
		if (files == null)
			return null;
		if (onlyIncludeFile)
			for (int i = 0; i < files.length; i++) {
				if (!files[i].isDirectory())
					vct.add(files[i].getName());
			}

		else
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory())
					vct.add(files[i].getName());
			}
		String[] strs = new String[vct.size()];
		vct.toArray(strs);
		return strs;
	}

	public static String[] listSubDir(String strAusolutedPath) {
		return listSubDir(strAusolutedPath, false);
	}

	public static String getRelativePath(String strBaseDir,
			String strAbsolutedPath) {
		strAbsolutedPath = FileSystemManager.processPath(strAbsolutedPath);
		strBaseDir = FileSystemManager.processPath(strBaseDir);
		int index = strAbsolutedPath.indexOf(strBaseDir);
		if (index < 0)
			return "";
		return strAbsolutedPath.substring(index + strBaseDir.length());
	}

	public static String getFileName(String strAbsolutedPath,
			boolean bWithExtension) {
		strAbsolutedPath = processPath(strAbsolutedPath);
		int index1;
		int index2;
		if ((index1 = strAbsolutedPath.lastIndexOf(".")) == -1)
			return "";
		if ((index2 = strAbsolutedPath.lastIndexOf("\\")) == -1
				&& (index2 = strAbsolutedPath.lastIndexOf("/")) == -1)
			return "";

		if (bWithExtension)
			return strAbsolutedPath.substring(index2 + 1);
		else
			return strAbsolutedPath.substring(index2 + 1, index1);
	}

	public static String getFileExtension(String strAbsolutedPath) {
		return strAbsolutedPath
				.substring(strAbsolutedPath.lastIndexOf(".") + 1);
	}

	public static String getFilePath(String strAbsolutedPath) {
		int index;
		if ((index = strAbsolutedPath.lastIndexOf("\\")) == -1
				&& (index = strAbsolutedPath.lastIndexOf("/")) == -1)
			return "";
		return strAbsolutedPath.substring(0, index + 1);
	}

	// public static boolean save(DataHandler dh, String path) {
	// if (dh == null) return false;
	// try {
	// dh.writeTo(new FileOutputStream(path));
	// } catch (FileNotFoundException fe) {
	// fe.printStackTrace();
	// return false;
	// } catch (IOException ie) {
	// ie.printStackTrace();
	// return false;
	// }
	// return true;
	// }

	public static synchronized boolean remove(String strFullPath) {
		if (!fileExisted(strFullPath))
			return true;
		File f = new File(strFullPath);
		if (f.isDirectory()) {
			File[] children = f.listFiles();
			for (int i = 0; i < children.length; i++) {
				if (!children[i].isFile())
					remove(children[i].getAbsolutePath());
				else
					children[i].delete();
			}
		}
		return f.delete();
	}

	public static boolean isReadOnly(String strFullPath) {
		return !(new File(strFullPath).canWrite());
	}

	public static final void copy(String sourceDir, String destDir) {
		if (!fileExisted(sourceDir))
			return;
		if (!fileExisted(destDir)) {
			if (!makeDir(destDir)) {
				if (!fileExisted(destDir))
					return;
			}
		}

		File f = new File(sourceDir);

		File[] fs = f.listFiles();
		for (int i = 0; i < fs.length; i++) {
			final File curF = fs[i];
			final String curName = destDir + "/" + curF.getName();
			if (fs[i].isDirectory())
				copy(curF.getAbsolutePath(), curName);
			else
				copyFile(curF.getAbsolutePath(), curName);
		}
	}

	public static final void copy(String sourceDir, String destDir,
			FilenameFilter filter, FilenameFilter dirFilter) {
		if (!fileExisted(sourceDir))
			return;
		if (!fileExisted(destDir)) {
			if (!makeDir(destDir)) {
				if (!fileExisted(destDir))
					return;
			}
		}

		File f = new File(sourceDir);

		File[] fs = f.listFiles();
		for (int i = 0; i < fs.length; i++) {
			final File curF = fs[i];
			String fn = curF.getName();
			if (curF.isFile() && !filter.accept(curF, fn))
				continue;
			if (curF.isDirectory() && dirFilter != null
					&& !dirFilter.accept(curF, fn))
				continue;
			final String curName = destDir + "/" + fn;
			if (curF.isDirectory())
				copy(curF.getAbsolutePath(), curName, filter, dirFilter);
			else
				copyFile(curF.getAbsolutePath(), curName);
		}
	}

	public static final void copyEx(String sourceDir, String destDir,
			String ignored) {
		if (!fileExisted(sourceDir))
			return;
		if (!fileExisted(destDir)) {
			if (!makeDir(destDir)) {
				if (!fileExisted(destDir))
					return;
			}
		}

		File f = new File(sourceDir);

		File[] fs = f.listFiles();
		for (int i = 0; i < fs.length; i++) {
			final File curF = fs[i];
			if (ignored.indexOf(curF.getName()) >= 0)
				continue;

			final String curName = destDir + "/" + curF.getName();
			if (fs[i].isDirectory())
				copyEx(curF.getAbsolutePath(), curName, ignored);
			else
				copyFile(curF.getAbsolutePath(), curName);
		}
	}

	public static void copyFile(final String source, final String dest) {
		if (!fileExisted(source)) {
			System.out.println("file '" + source + "' doesn't exist!");
			return;
		}

		String path = getFilePath(dest);
		if (!fileExisted(path))
			makeDir(path);

		try {
			FileInputStream in = new FileInputStream(source);
			FileOutputStream out = new FileOutputStream(dest);

			byte[] bs = new byte[3072];
			int count = 0;
			while ((count = in.read(bs)) != -1) {
				out.write(bs, 0, count);
				out.flush();
			}

			in.close();
			out.close();
		} catch (FileNotFoundException fe) {
			fe.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		}
	}

	public static boolean isFile(String path) {
		if (!fileExisted(path))
			return false;
		return new File(path).isFile();
	}

	public static void main(String[] args) throws Exception {
		FilenameFilter f = new FilenameFilter() {
			public boolean accept(File dir, String fileName) {
				return fileName.endsWith(".txt");
			}
		};
		FileSystemManager.copy("d:\\temp", "d:\\test", f, f);
	}
}
